package org.design.serial;

import lombok.extern.slf4j.Slf4j;
import org.design.serial.constant.Constant;
import org.design.serial.dao.SerialInfoDao;
import org.design.serial.dao.SerialRuleDao;
import org.design.serial.dto.GenSerialParam;
import org.design.serial.entity.SerialInfo;
import org.design.serial.entity.SerialRule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * SerialService
 *
 * @author 樊温军
 * @date 2025/6/14 下午2:10
 */
@Slf4j
@Component
public class SerialService {

    private SerialRuleDao serialRuleDao;
    private SerialInfoDao serialInfoDao;

    @Autowired
    public void setSerialRuleDao(SerialRuleDao serialRuleDao) {
        this.serialRuleDao = serialRuleDao;
    }

    @Autowired
    public void setSerialInfoDao(SerialInfoDao serialInfoDao) {
        this.serialInfoDao = serialInfoDao;
    }

    @Transactional(rollbackFor = Exception.class)
    public String generateSerialNumber(GenSerialParam genSerialParam) {
        // 获取规则
        SerialRule serialRule = serialRuleDao.getReferenceById("1");
        String rule = serialRule.getRule();
        if (rule == null) {
            throw new RuntimeException("规则不存在");
        }
        Map<String, String> map = getRulesMap(rule, genSerialParam);

        int loop = 5;
        int start = 0;
        String code = "";
        while (start < loop) {
            try {
                code = generateCode(map, serialRule);
            } catch (Exception ignored) {
            }

            if (code != null && !code.isEmpty()) {
                break;
            } else {
                start++;
            }
        }
        if (start >= loop) {
            throw new RuntimeException("生成编码异常");
        }
        return code;
    }

    private String generateCode(Map<String, String> map, SerialRule serialRule) {
        String keyWord = map.get("keyWord");
        if (keyWord == null || keyWord.isEmpty()) {
            throw new RuntimeException("规则关键字不能为空");
        }
        SerialInfo serialInfo = serialInfoDao.getByRuleIdAndKeyWord(serialRule.getId(), keyWord);
        String rules = map.get("rules");
        String numRule = map.get("numRule");
        String numValue = map.get("numValue");

        if (serialInfo != null) {
            Integer currentSerialNumber = serialInfo.getCurrentSerialNumber();
            Integer newCurrentSerialNumber = currentSerialNumber + 1;
            String formattedNumber = String.format("%0" + numValue + "d", newCurrentSerialNumber);
            String replace = rules.replace(numRule, formattedNumber);
            int i = serialInfoDao.updateByNumAndId(replace, serialInfo.getId(), newCurrentSerialNumber,
                    currentSerialNumber);
            log.info(String.format("replace:%s,id:%s,newCurrentSerialNumber:%s,currentSerialNumber:%s",
                    replace, serialInfo.getId(), newCurrentSerialNumber, currentSerialNumber));
            if (i > 0) {
                return replace;
            }
        } else {
            SerialInfo save = new SerialInfo();
            save.setKeyword(keyWord);
            save.setRuleId(serialRule.getId());
            String formattedNumber = String.format("%0" + numValue + "d", 1);
            String replace = rules.replace(numRule, formattedNumber);
            save.setCurrentCodeNumber(replace);
            save.setCurrentSerialNumber(1);
            serialInfoDao.save(save);
            return replace;
        }
        return null;
    }

    private Map<String, String> getRulesMap(String rules, GenSerialParam genSerialParam) {

        Map<String, String> map = new HashMap<>();
        String keyWord = genSerialParam.getBizCode();

        Pattern pattern1 = Pattern.compile(Constant.M_PATTERN_1);
        Pattern pattern2 = Pattern.compile(Constant.M_PATTERN_2);
        Pattern pattern3 = Pattern.compile(Constant.M_PATTERN_3);
        Pattern pattern4 = Pattern.compile(Constant.M_PATTERN_4);
        Pattern pattern5 = Pattern.compile(Constant.M_PATTERN_5);

        Map<String, Object> params = genSerialParam.getParams();

        Matcher matcher = pattern1.matcher(rules);
        rules = getRules(rules, matcher, params);
        Matcher matcher2 = pattern2.matcher(rules);
        while (matcher2.find()) {
            String matcherMethod = matcher2.group(1);
            if (matcherMethod != null && !matcherMethod.isEmpty()) {
                Object o = params.get(matcherMethod);
                if (ObjectUtils.isEmpty(o)) {
                    throw new RuntimeException("业务参数%{" + matcherMethod + "}不存在");
                }
                String bs = String.valueOf(o);
                keyWord = keyWord.concat(bs);
                rules = rules.replace("${".concat(matcherMethod).concat("}"), bs);
            }

        }
        Matcher matcher3 = pattern3.matcher(rules);
        rules = getRules(rules, matcher3);

        Matcher matcher4 = pattern4.matcher(rules);
        while (matcher4.find()) {
            String matcherMethod = matcher4.group(1);
            if (matcherMethod != null && !matcherMethod.isEmpty()) {
                SimpleDateFormat sdf = new SimpleDateFormat(matcherMethod);
                String format;
                if (genSerialParam.getDate() != null) {
                    format = sdf.format(new Date(genSerialParam.getDate()));
                } else {
                    format = sdf.format(new Date());
                }
                keyWord = keyWord.concat(format);
                rules = rules.replace("$[".concat(matcherMethod).concat("]"), format);
            }
        }

        Matcher matcher5 = pattern5.matcher(rules);
        while (matcher5.find()) {
            String matcherMethod = matcher5.group(1);
            if (matcherMethod != null && !matcherMethod.isEmpty()) {
                String numRule = "$(".concat(matcherMethod).concat(")");
                map.put("numRule", numRule);
                map.put("numValue", matcherMethod);
                break;
            }
        }
        map.put("rules", rules);
        map.put("keyWord", keyWord);
        return map;
    }

    private static String getRules(String rules, Matcher matcher3) {
        while (matcher3.find()) {
            String matcherMethod = matcher3.group(1);
            if (matcherMethod != null && !matcherMethod.isEmpty()) {
                SimpleDateFormat sdf = new SimpleDateFormat(matcherMethod);
                String format = sdf.format(new Date());
                rules = rules.replace("%[".concat(matcherMethod).concat("]"), format);
            }
        }
        return rules;
    }

    private static String getRules(String rules, Matcher matcher, Map<String, Object> params) {
        while (matcher.find()) {
            String matcherMethod = matcher.group(1);
            if (matcherMethod != null && !matcherMethod.isEmpty()) {
                Object o = params.get(matcherMethod);
                if (ObjectUtils.isEmpty(o)) {
                    throw new RuntimeException("业务参数%{" + matcherMethod + "}不存在");
                }
                rules = rules.replace("%{".concat(matcherMethod).concat("}"), String.valueOf(o));
            }
        }
        return rules;
    }
}
